local m_3v3_desc = [[
  
# 3v3模式简介

  六名玩家3v3进行对战的竞技模式。
  
  若为“统帅三军”规则，则改为两名玩家1v1对战，每名玩家控制三名角色（统帅三军模式暂无）。

  3v3模式规则历年经过多次修改，新月杀采用的是2023版王者之战规则。

  ___

  ## 阵营分布

  分为暖色方、冷色方双方阵营，每阵营为一名“主帅”和两名“先锋”。暖色方身份牌为红色，冷色方身份牌为蓝色。

  座次固定为：冷方先锋A-冷方主帅-冷方先锋B-暖方先锋A-暖方主帅-暖方先锋B

  ___

  ## 胜利条件

  消灭敌方阵营的主帅。

  ___

  ## 选将流程

  游戏开始前，展示16张公共武将牌，由双方主帅为本方阵营挑选武将。

  由暖色方开始，按1-2-2-...-2-1的数量，双方交替选择武将。
  
  完成选将后，主帅为本方的三名角色选择武将，然后同时亮出，游戏开始。

  ___

  ## 初始体力与手牌

  主帅的初始体力上限和初始体力值+1，但不会获得主公技。

  暖色方主帅初始手牌数+1。

  ___

  ## 行动顺序

  行动顺序是3v3模式与其他游戏模式最大的区别。

  每轮游戏分为四个行动单元。每个行动单元中，主帅选择：1.自己行动；2.选择一名本方先锋，该先锋行动，然后另一名先锋行动。

  1. 由冷色方开始，执行一个行动单元；
  
  2. 然后暖色方执行一个行动单元；

  3. 冷色方执行剩余的一个行动单元（即：若第一个行动单元时选择主帅行动，则此时两名先锋行动；若第一个行动单元时选择两名先锋行动，则此时主帅行动）；
  
  4. 最后再由暖色方执行最后一个行动单元。

  5. 所有角色都行动后，完成一轮。

  线下模式中，会将身份牌横置以表示本轮已行动。在新月杀中，为行动的角色增加“已行动”标记（小红旗）以表示本轮已行动。

  ___

  ## 击杀奖惩

  击杀一名先锋角色后，摸两张牌。（贴吧早年梗：冷主收边）

  ___

  ## 特殊规则

  本模式AOE卡牌（【南蛮入侵】、【万箭齐发】、【桃园结义】、【五谷丰登】）在使用前，使用者选择按顺时针或逆时针方向进行结算。

  ___

  ## 游戏牌堆

  本模式采用特殊的精简后的标准版+军争牌堆，牌堆列表参见卡牌一览。

  注意，部分卡牌效果进行了修改：

  - 【无中生有】：出牌阶段，对你使用，目标角色摸两张牌。若己方角色数少于敌方角色数，则多摸一张牌。
  - 【诸葛连弩】替换为【连弩】：锁定技，你于出牌阶段内使用【杀】次数上限+3。

  ___

  ## 武将牌堆

  采用专用的竞技将池，部分武将技能进行了修改。
  
  新月杀中采用各版将池的并集，游玩时可以根据个人喜好酌情禁用。

  | 魏 | 蜀 | 吴 | 群 |
  | ---- | ---- | ---- | ---- |
  | 2023版： |  |  |  |
  | 曹操（界） | 诸葛亮（标） | 孙权（标） | 华佗（界） |
  | 司马懿（界） | 马超（界） | 甘宁（界） | 吕布（专属） |
  | 张辽（界） | 黄月英（界） | 大乔（界） | 貂蝉（标） |
  | 甄姬（标） | 姜维（手杀界） | 孙尚香（界） | 伏完 |
  | 典韦（手杀界） | 徐庶（一将） | 孙策（手杀界） | SP孙策 |
  | 李典 | 法正 | 诸葛瑾（专属） |  |
  | 文聘（专属） | 孙乾 | 徐盛（专属） |  |
  | 郭淮（新服界） | 黄权（专属） | 凌统 |  |
  |  |  | 韩当 |  |
  |  |  | 虞翻 |  |
  |  |  | 顾雍 |  |
  |  |  | 凌操（手杀） |  |
  | 2019版：|  |  |  |
  | 曹操（界） | 刘备（标） | 孙权（标） | 华佗（标） |
  | 司马懿（界） | 关羽（专属） | 甘宁（界） | 吕布（专属） |
  | 夏侯惇（专属） | 张飞（标） | 周瑜（界） | 貂蝉（标） |
  | 张辽（标） | 诸葛亮（标） | 大乔（标） | 庞德（OL界） |
  | 许褚（界） | 赵云（界） | 孙尚香（标） | 陈宫 |
  | 郭嘉（标） | 马超（界） | 小乔（界） | 伏完 |
  | 甄姬（标） | 黄月英（标） | 孙坚 |  |
  | 典韦（手杀界） | 姜维 | 孙策 |  |
  | 徐晃（手杀界） | 陈到 | 诸葛瑾（专属） |  |
  | 李典 | 黄权（专属） | 虞翻 |  |
  | 文聘（专属） | 马谡（RE） | 顾雍 |  |
  |  | 周仓 |  |  |
  | 2013版：|  |  |  |
  | 曹操 | 刘备 | 孙权 | 华佗 |
  | 司马懿 | 关羽（专属） | 甘宁 | 吕布（专属） |
  | 夏侯惇（专属） | 张飞 | 黄盖 | 貂蝉 |
  | 张辽 | 诸葛亮 | 周瑜 | 庞德 |
  | 郭嘉 | 赵云（专属） | 大乔 | 贾诩 |
  | 甄姬 | 马超 | 孙尚香 |  |
  | 夏侯渊 | 黄月英 | 小乔 |  |
  | 徐晃 | 姜维 | 孙坚 |  |
  | 文聘（专属） |  | 孙策 |  |
  |  |  | 诸葛瑾（专属） |  |
  | 2012版：|  |  |  |
  | 曹操 | 刘备 | 孙权 | 华佗 |
  | 司马懿 | 关羽 | 甘宁 | 吕布 |
  | 张辽 | 张飞 | 黄盖 | 貂蝉 |
  | 许褚 | 诸葛亮 | 周瑜 | 庞德 |
  | 郭嘉 | 赵云 | 陆逊 |  |
  | 甄姬 | 马超 | 大乔 |  |
  | 夏侯渊 | 黄月英 | 孙尚香 |  |
  | 徐晃 | 黄忠 | 小乔 |  |
  |  | 孟获 | 周泰 |  |
  |  |  | 孙坚 |  |
  |  |  | 诸葛瑾（专属） |  |
]]

local m_3v3_getLogic = function()
  local m_3v3_logic = GameLogic:subclass("m_3v3_logic") ---@class GameLogic

  function m_3v3_logic:initialize(room)
    GameLogic.initialize(self, room)
    self.role_table = {
      {"cool_vanguard", "cool_marshal", "cool_vanguard", "warm_vanguard", "warm_marshal", "warm_vanguard"},
    }
  end

  function m_3v3_logic:assignRoles()
    local room = self.room
    local roles = self.role_table[math.random(1, 1)]
    table.shuffle(room.players)
    for i = 1, #room.players do
      local p = room.players[i]
      p.role = roles[i]
      room:setPlayerProperty(p, "role_shown", true)
      room:broadcastProperty(p, "role")
    end
    room:setCurrent(room.players[1])
  end

  function m_3v3_logic:chooseGenerals()
    local room = self.room
    math.randomseed(tonumber(tostring(os.time()):reverse():sub(1, 6)))

    local cool_marshal = room.players[2]
    local warm_marshal = room.players[5]
    room:setCurrent(cool_marshal)

    local general_pool = {
      --2023
      "ty_ex__guohuai",
      "ex__huangyueying", "m_ex__jiangwei", "xushu", "fazheng", "sunqian",
      "ex__daqiao", "ex__sunshangxiang", "m_ex__sunce", "lingtong", "handang", "lingcao",
      "ol_sp__sunce",
      --2019
      "ex__caocao", "ex__simayi", "ex__xuchu", "m_ex__dianwei", "m_ex__xuhuang", "lidian",
      "ex__zhaoyun", "ex__machao", "chendao", "re__masu", "zhoucang",
      "ex__ganning", "ex__zhouyu", "ol_ex__xiaoqiao", "yufan", "guyong",
      "ol_ex__pangde", "chengong", "fuwan",
      --2013
      "jiangwei", "sunce", "jiaxu",
      --2012
      "caocao", "simayi", "zhaoliao", "xuchu", "guojia", "zhenji", "xiahouyuan", "xuhuang",
      "liubei", "guanyu", "zhangfei", "zhugeliang", "zhaoyun", "machao", "huangyueying", "huangzhong", "menghuo",
      "sunquan", "ganning", "huanggai", "zhouyu", "luxun", "daqiao", "sunshangxiang", "xiaoqiao", "zhoutai", "sunjian",
      "huatuo", "lvbu", "diaochan", "pangde",
    }
    local trueNames = {}
    for _, name in ipairs(room.general_pile) do
      if not trueNames[name] then
        trueNames[name] = true
      end
    end
    for _, general in ipairs(general_pool) do
      if Fk.generals[general] and not trueNames[Fk.generals[general].trueName] then
        table.insert(room.general_pile, general)  --加入未在白名单内的trueName，eg.姜维孙策，外部扩展
        trueNames[Fk.generals[general].trueName] = true
      end
    end
    table.shuffle(room.general_pile)
    local all_generals = room:getNGenerals(16)
    if #all_generals < 16 then
      room:sendLog{
        type = "#NoGeneralDraw",
        toast = true,
      }
      room:gameOver("")
    end

    local cool_generals, warm_generals = {}, {}
    local cool_selected, warm_selected = {}, {}

    local updataGeneralPile = function(p)
      if p == cool_marshal then
        room:setBanner("@&cool_generals", cool_generals)
      else
        room:setBanner("@&warm_generals", warm_generals)
      end
    end
    local function chooseGeneral(p, n)
      local prompt = "#3v3_mode-choose:::"..(p == cool_marshal and "firstPlayer" or "secondPlayer")..":"..n
      local my_selected = (p == cool_marshal) and cool_selected or warm_selected
      local ur_selected = (p == cool_marshal) and warm_selected or cool_selected
      local my_genrals = (p == cool_marshal) and cool_generals or warm_generals
      local result = room:askForCustomDialog(p, "m_3v3_mode", "packages/gamemode/qml/1v1.qml",
      { all_generals, n, my_selected, ur_selected, prompt } )
      local selected = {}
      if result ~= "" then
        result = json.decode(result)
        for i, id in ipairs(result.ids) do
          local g = result.generals[i]
          -- 更新武将替换
          all_generals[id+1] = g
          table.insert(my_selected, id)
          table.insert(my_genrals, g)
          table.insert(selected, g)
        end
      else
        local selected_list = table.connect(my_selected, ur_selected)
        for i, g in ipairs(all_generals) do
          if not table.contains(selected_list, i-1) then
            table.insert(my_selected, i-1)
            table.insert(my_genrals, g)
            table.insert(selected, g)
            if #selected == n then break end
          end
        end
      end
      room:sendLog{
        type = "#1v1ChooseGeneralsLog",
        arg = p == cool_marshal and "cool" or "warm",
        arg2 = selected[1],
        arg3 = selected[2] or "",
        toast = true,
      }
      updataGeneralPile(p)
    end

    chooseGeneral(warm_marshal, 1)
    chooseGeneral(cool_marshal, 2)
    chooseGeneral(warm_marshal, 2)
    chooseGeneral(cool_marshal, 2)
    chooseGeneral(warm_marshal, 2)
    chooseGeneral(cool_marshal, 2)
    chooseGeneral(warm_marshal, 2)
    chooseGeneral(cool_marshal, 2)
    chooseGeneral(warm_marshal, 1)

    local req = Request:new({cool_marshal, warm_marshal}, "AskForGeneral")
    req:setData(cool_marshal, { cool_generals, 3, true })
    req:setDefaultReply(cool_marshal, table.random(cool_generals, 3))
    req:setData(warm_marshal, { warm_generals, 3, true })
    req:setDefaultReply(warm_marshal, table.random(warm_generals, 3))

    room:doBroadcastNotify("ShowToast", Fk:translate("3v3_choose_general"), {cool_marshal, warm_marshal})
    req:ask()

    room:setBanner("@&cool_generals", 0)
    room:setBanner("@&warm_generals", 0)

    local generals = {}
    table.insertTable(generals, req:getResult(cool_marshal))
    table.insertTable(generals, req:getResult(warm_marshal))

    for i = 1, 6, 1 do
      local p = room.players[i]
      room:setPlayerGeneral(p, generals[i], true, true)
      room:broadcastProperty(p, "general")
    end
  end

  function m_3v3_logic:attachSkillToPlayers()
    local room = self.room
    local addRoleModSkills = function(player, skillName)
      local skill = Fk.skills[skillName]
      if not skill then
        fk.qCritical("Skill: "..skillName.." doesn't exist!")
        return
      end
      if skill.lordSkill then
        return
      end
      if #skill.attachedKingdom > 0 and not table.contains(skill.attachedKingdom, player.kingdom) then
        return
      end

      room:handleAddLoseSkills(player, skillName, nil, false)
    end
    for _, p in ipairs(room.alive_players) do
      for _, s in ipairs(Fk.generals[p.general]:getSkillNameList(false)) do
        addRoleModSkills(p, s)
      end
      if p.deputyGeneral ~= "" then
        for _, s in ipairs(Fk.generals[p.deputyGeneral]:getSkillNameList(false)) do
          addRoleModSkills(p, s)
        end
      end
    end
  end

  ---@class m_3v3_Round: GameEvent.Round
  local m_3v3_Round = GameEvent.Round:subclass("m_3v3_Round")
  function m_3v3_Round:action()
    local room = self.room
    local cool_marshal = table.find(room.players, function (p)
      return p.role == "cool_marshal"
    end)
    local warm_marshal = table.find(room.players, function (p)
      return p.role == "warm_marshal"
    end)
    local function CommandAction(marshal)
      local friends = table.filter(room.alive_players, function (p)
        return marshal.role[1] == p.role[1] and p:getMark("@!action-round") == 0
      end)
      if #friends > 0 then
        local to
        if #friends > 1 then
          to = room:askForChoosePlayers(marshal, table.map(friends, Util.IdMapper), 1, 1,
            "#m_3v3_action", "m_3v3_gamerule", false)
          to = room:getPlayerById(to[1])
        else
          to = friends[1]
        end
        room:setCurrent(to)
        room:setPlayerMark(to, "@!action-round", 1)
        GameEvent.Turn:create(to):exec()
        while to ~= marshal do
          if room.game_finished then break end
          local vanguards = table.filter(room.alive_players, function (p)
            return p.role:endsWith("vanguard") and marshal.role[1] == p.role[1] and p:getMark("@!action-round") == 0
          end)
          if #vanguards > 0 then
            if #vanguards > 1 then
              to = room:askForChoosePlayers(marshal, table.map(vanguards, Util.IdMapper), 1, 1,
                "#m_3v3_action", "m_3v3_gamerule", false)
              room:setCurrent(to)
              room:setPlayerMark(to, "@!action-round", 1)
              GameEvent.Turn:create(to):exec()
            else
              to = vanguards[1]
              room:setCurrent(to)
              room:setPlayerMark(to, "@!action-round", 1)
              GameEvent.Turn:create(to):exec()
            end
          else
            break
          end
        end
      end
    end
    while table.find(room.alive_players, function (p)
      return p:getMark("@!action-round") == 0
    end) do
      if room.game_finished then break end
      CommandAction(cool_marshal)
      if room.game_finished then break end
      CommandAction(warm_marshal)
    end
  end

  function m_3v3_logic:action()
    self:trigger(fk.GamePrepared)
    local room = self.room
    room:setTag("SkipNormalDeathProcess", true)

    GameEvent.DrawInitial:create():exec()

    while true do
      m_3v3_Round:create():exec()
      if room.game_finished then break end
    end
  end

  return m_3v3_logic
end

local m_3v3_rule = fk.CreateTriggerSkill{
  name = "#m_3v3_rule",
  priority = 0.001,
  mute = true,
  events = {fk.DrawInitialCards, fk.GameOverJudge, fk.Deathed, fk.PreCardUse, fk.BeforeDrawCard},
  can_trigger = function (self, event, target, player, data)
    return target == player and not (event == fk.Deathed and player.rest > 0)
  end,
  on_cost = Util.TrueFunc,
  on_use = function(self, event, target, player, data)
    local room = player.room
    if event == fk.DrawInitialCards then
      if player.seat == 5 then
        data.num = data.num + 1
      end
    elseif event == fk.GameOverJudge then
      room:setTag("SkipGameRule", true)
      if target.role == "cool_marshal" then
        room:gameOver("warm")
        return true
      elseif target.role == "warm_marshal" then
        room:gameOver("cool")
        return true
      end
    elseif event == fk.Deathed and target.role:endsWith("vanguard") then
      local damage = data.damage
      if damage and damage.from and not damage.from.dead then
        damage.from:drawCards(2, "kill")
      end
    elseif event == fk.PreCardUse then
      if data.card.multiple_targets and data.card.skill.min_target_num == 0 then
        local choice = room:askForChoice(player, {"left", "right"}, "m_3v3_gamerule",
          "#m_3v3_aoe-choice:::"..data.card:toLogString())
        if choice == "left" then
          data.extra_data = data.extra_data or {}
          data.extra_data.m_3v3_reverse = true
        end
      end
    elseif event == fk.BeforeDrawCard and data.skillName == "ex_nihilo" then  --转化出的原版无中（eg.孙乾），按理来说应该改卡牌的skill
      if 2 * #table.filter(room.alive_players, function (p)
        return p.role[1] == target.role[1]
      end) < #room.alive_players then
        data.num = data.num + 1
      end
    end
  end,

  refresh_events = {fk.BeforeCardUseEffect},
  can_refresh = function(self, event, target, player, data)
    return player.seat == 1 and data.extra_data and data.extra_data.m_3v3_reverse and
      #TargetGroup:getRealTargets(data.tos) > 0
  end,
  on_refresh = function(self, event, target, player, data)
    local room = player.room
    local new_tos = {}
    local players = {room.current}
    table.insertTable(players, table.reverse(room:getOtherPlayers(room.current)))
    for _, p in ipairs(players) do
      for _, info in ipairs(data.tos) do
        if info[1] == p.id then
          table.insert(new_tos, info)
          break
        end
      end
    end
    data.tos = new_tos
  end,
}
Fk:addSkill(m_3v3_rule)

local m_3v3_mode = fk.CreateGameMode{
  name = "m_3v3_mode",
  minPlayer = 6,
  maxPlayer = 6,
  logic = m_3v3_getLogic,
  rule = m_3v3_rule,
  surrender_func = function(self, playedTime)
    if Self.role:endsWith("vanguard") then
      return { { text = "vanguard_never_surrender", passed = false } }
    else
      local canSurrender = true
      if table.find(Fk:currentRoom().players, function(p)
        return (p.rest > 0 or not p.dead) and p ~= Self and p.role[1] == Self.role[1]
      end) then
        canSurrender = false
      end
      return { { text = "marshal_surrender", passed = canSurrender } }
    end
  end,
  whitelist = {
    "3v3_cards",

    "3v3_generals",
    --[[
    "standard",
    "standard_ex",
    "m_shzl_ex",
    "wind",
    "fire",
    "forest",
    "ol_sp1",
    "yjcm2011",
    "yjcm2012",
    "yjcm2013",]]--
  },
  winner_getter = function(self, victim)
    if not victim.surrendered and victim.rest > 0 then
      return ""
    end
    if victim.role == "cool_marshal" then
      return "warm_marshal+warm_vanguard"
    elseif victim.role == "warm_marshal" then
      return "cool_marshal+cool_vanguard"
    end
    return ""
  end,
  get_adjusted = function(self, player)
    if player.role:endsWith("marshal") then
      return {hp = player.hp + 1, maxHp = player.maxHp + 1}
    end
    return {}
  end,
  build_draw_pile = function(self)
    local draw, void = GameMode.buildDrawPile(self)
    local room = Fk:currentRoom()

    for i = #draw, 1, -1 do
      local id = draw[i]
      local card = Fk:getCardById(id)
      if card.name == "lightning" then
        table.remove(draw, i)
        table.insert(void, id)
      elseif card.name == "ex_nihilo" then
        table.insert(void, id)
        local newCard = AbstractRoom.printCard(room, "v33__ex_nihilo", card.suit, card.number)
        draw[i] = newCard.id
      elseif card.name == "crossbow" then
        table.insert(void, id)
        local newCard = AbstractRoom.printCard(room, "xbow", card.suit, card.number)
        draw[i] = newCard.id
      end
    end

    return draw, void
  end
}

Fk:loadTranslationTable{
  ["m_3v3_mode"] = "3v3",
  [":m_3v3_mode"] = m_3v3_desc,
  ["cool"] = "冷色方",
  ["warm"] = "暖色方",
  ["cool_marshal"] = "冷方主帅",
  ["warm_marshal"] = "暖方主帅",
  ["cool_vanguard"] = "冷方先锋",
  ["warm_vanguard"] = "暖方先锋",

  ["#3v3_mode-choose"] = "你是[%arg]，请选择 %arg2 张武将牌作为备选",
  ["#3v3ChooseGeneralsLog"] = "%arg 选择了 %arg2 %arg3",
  ["3v3_choose_general"] = "请为本方阵营选择选择武将，从左至右为：左方先锋 主帅 右方先锋",
  ["@&cool_generals"] = "冷方已选武将",
  ["@&warm_generals"] = "暖方已选武将",

  ["m_3v3_gamerule"] = "选择",
  ["#m_3v3_action"] = "选择一名友方角色行动",

  ["#m_3v3_aoe-choice"] = "选择你使用%arg结算的方向",
  ["left"] = "←顺时针方向",
  ["right"] = "逆时针方向→",

  ["cool_marshal+cool_vanguard"] = "冷色方",
  ["warm_marshal+warm_vanguard"] = "暖色方",
  ["vanguard_never_surrender"] = "先锋永不投降！",
  ["marshal_surrender"] = "本阵营先锋均阵亡",
}

return m_3v3_mode
